package jupl.file.host;

import static migool.util.HtmlParserUtil.FILE_INPUT_FILTER;
import static migool.util.HtmlParserUtil.NAME;
import static migool.util.HtmlParserUtil.fillParams;
import static migool.util.HtmlParserUtil.getFileForm;
import static migool.util.HtmlParserUtil.getLoginForm;
import static migool.util.HtmlParserUtil.setHiddenInputs;
import static migool.util.HtmlParserUtil.toListNameValuePair;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import jupl.file.FileUploadException;
import jupl.file.FileUploadResponse;
import jupl.file.FileUploaderBase;
import migool.auth.Login;
import migool.auth.LoginException;
import migool.entity.CaptchaEntity;
import migool.http.client.HttpClientWrapper;
import migool.util.LinkUtil;
import migool.util.RegexUtil;

import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.htmlparser.tags.FormTag;
import org.htmlparser.tags.InputTag;
import org.htmlparser.util.ParserException;

/**
 * @author Denis Migol
 * 
 */
public class DepositfilesComUploader extends FileUploaderBase {

	public static final String HOST = "depositfiles.com";

	private String uploadHtml = null;
	private Login login = null;

	private final HttpClientWrapper client = new HttpClientWrapper();

	public DepositfilesComUploader() {
		super(HOST);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jupl.file.FileUploader#upload(java.io.File)
	 */
	@Override
	public FileUploadResponse upload(final File file) throws IOException, FileUploadException {
		if (login == null) {
			throw new FileUploadException();
		}
		if (uploadHtml == null) {
			uploadHtml = client.getToString(LinkUtil.createHttpRoot(host));
		}
		FormTag uploadForm;
		try {
			uploadForm = getFileForm(uploadHtml);
		} catch (final ParserException e) {
			throw new FileUploadException();
		}
		if (uploadForm == null) {
			throw new FileUploadException();
		}
		final InputTag fileInput = (InputTag) uploadForm.getChildren()
				.extractAllNodesThatMatch(FILE_INPUT_FILTER, true).elementAt(0);
		if (fileInput == null) {
			throw new FileUploadException();
		}

		final Map<String, String> params = new HashMap<String, String>();
		setHiddenInputs(uploadForm, params);
		final MultipartEntity entity = new MultipartEntity();
		entity.addPart(fileInput.getAttribute(NAME), new FileBody(file));

		final HttpPost request = new HttpPost(uploadForm.extractFormLocn());
		fillParams(entity, params);
		request.setEntity(entity);
		return new FileUploadResponse(RegexUtil.getMatch(client.requestToString(request),
				"http\\:\\/\\/depositfiles\\.com\\/files\\/[\\w]{6,9}"));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see migool.auth.Loginable#getLoginCaptcha()
	 */
	@Override
	public CaptchaEntity getLoginCaptcha() throws IOException {
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see migool.auth.Loginable#login(migool.auth.Login)
	 */
	@Override
	public void login(final Login login) throws LoginException, IOException {
		final HttpClientWrapper client = this.client;
		final String url = LinkUtil.createHttpRoot(host);

		FormTag loginForm;
		try {
			loginForm = getLoginForm(client.getToString(url));
		} catch (final ParserException e) {
			throw new LoginException(e);
		}
		if (loginForm == null) {
			throw new LoginException();
		}

		final Map<String, String> params = new HashMap<String, String>();
		setHiddenInputs(loginForm, params);
		params.put("login", login.getUsername());
		params.put("password", login.getPassword());

		final HttpPost request = new HttpPost(loginForm.getFormLocation());
		request.setEntity(new UrlEncodedFormEntity(toListNameValuePair(params)));
		client.requestToString(request);
		if (!(uploadHtml = client.getToString(url)).contains(login.getUsername())) {
			uploadHtml = null;
			throw new LoginException();
		}
		this.login = login;
	}

}
